package com.chance.cc.crawler.development.scripts.xiaohongshu.phone;

import com.alibaba.fastjson.JSON;
import com.chance.cc.crawler.meta.core.bean.crawler.CrawlerDomainKeys;
import com.chance.cc.crawler.sheduler.job.context.ScheduleHandlerContext;
import com.chance.cc.crawler.sheduler.job.handler.SchedulerHandler;
import com.chance.cc.crawler.sheduler.utils.GlobalCacheUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import se.vidstige.jadb.JadbDevice;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Base64;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

import static com.chance.cc.crawler.sheduler.job.handler.phone.AdbShellUtils.*;

/**
 * @author bx
 * @date 2020/12/4 0004 11:28
 */
public class XHSPhoneSearchForTimeLineMI5SADBScript extends SchedulerHandler{

    private static Logger log = LoggerFactory.getLogger(XHSPhoneSearchForTimeLineMI5SADBScript.class);

//    private static AtomicBoolean isHandle = new AtomicBoolean(true);
    public static final String log_prefix = "device {} xhs search kw ";
    public static final String cacheKey = "crawler_domain_keywords_cache_keys";

    @Override
    public String domain() {
        return "xhs";
    }

    @Override
    public boolean isHandle(ScheduleHandlerContext context) {

        Map<String, String> scheduleDataMap = context.getScheduleDataMap();

        Object obj = GlobalCacheUtils.getInstance().get(scheduleDataMap.get(cacheKey));
        if (obj == null ){
            log.error("xhs search job data has to config cache key!");
            return false;
        }

        if (!(obj instanceof LinkedBlockingQueue)){
            log.error("xhs search cache value type needs to be LinkedBlockingDeque!");
            return false;
        }

        return true;
    }

    @Override
    public void handle(ScheduleHandlerContext context) {

        //do some thing
        JadbDevice jadbDevice = context.getJadbDevice();
        Map<String, String> scheduleDataMap = context.getScheduleDataMap();

        LinkedBlockingQueue<CrawlerDomainKeys> crawlerDomainKeys =
                (LinkedBlockingQueue<CrawlerDomainKeys>) GlobalCacheUtils.getInstance().get(scheduleDataMap.get(cacheKey));
        int swipeNumbers = Integer.valueOf(scheduleDataMap.getOrDefault("phone_swipe_numbers", "50"));

        while (true){

            if(!checkAvailable(jadbDevice)){
                continue;
            }

            CrawlerDomainKeys domainKeys = null;
            try {
                domainKeys = crawlerDomainKeys.poll(10, TimeUnit.SECONDS);

                if (domainKeys == null){
                    String address = crawlerDomainKeys.getClass().getName() +
                            "@" + Integer.toHexString(crawlerDomainKeys.hashCode());

                    log.info("devices {} obtain keyword is null,cache key {}, queue address {},current job is finish!",
                            jadbDevice.getSerial(),address,scheduleDataMap.get(cacheKey));
                    break;
                }
            } catch (InterruptedException e) {
                log.error(e.getMessage());
            }

            String keyWord = domainKeys.getKeyword();
            Map map = JSON.parseObject(keyWord, Map.class);
            keyWord = map.get("keyword").toString();
            try {
                xhsKeyWordSearch(jadbDevice,keyWord,swipeNumbers,context);
            } catch (Exception e) {
                log.error("xhs device {} search kw {} error {},will retry!",
                        jadbDevice.getSerial(),keyWord,e.getMessage());
                crawlerDomainKeys.add(domainKeys);
            }
        }

    }

    public static void xhsKeyWordSearch(JadbDevice device, String keyword, int swipeNumbers,ScheduleHandlerContext context)  throws Exception {
        log.info(log_prefix +"script--begin------------------",device.getSerial());

        //当前是否是在初始页面
        if(!initHome(device)){
            throw new Exception("无法初始到home页！");
        }

        //采集关键词
        xhsSearchKeyWord(device,keyword,swipeNumbers);

        //返回到xhs首页
        executeShell(2000,device,"input keyevent 4");
        executeShell(2000,device,"input keyevent 4");
        executeShell(2000,device,"input keyevent 4");
        log.info(log_prefix +"返回小红书首页",device.getSerial());
    }

    private static void  xhsSearchKeyWord(JadbDevice device, String keyword, int swipeNumbers) throws Exception {
        executeShell(device,"ime set com.android.adbkeyboard/.AdbIME");
        log.info("device {} dy kw search 切换adb输入法",device.getSerial());

        String encode = Base64.getEncoder().encodeToString(keyword.getBytes());
        executeShell(device,"adb -s "+device.getSerial()+" shell am broadcast -a ADB_INPUT_B64 --es msg "+encode,true);//文本输入
        log.info(log_prefix +"script--输入需要查询的关键词[{}]",device.getSerial(),keyword);

        String[] searchCoordinate = getCoordinate(dumpUI(device),"text", "搜索");
        executeShell(5000,device,"input tap "+searchCoordinate[0]+" "+searchCoordinate[1]);
        log.info(log_prefix +"点击搜索按钮",device.getSerial());

        ByteArrayOutputStream baos = dumpUIForOutPutStream(device,5);
        String[] endCoordinate = getCoordinate(new ByteArrayInputStream(baos.toByteArray()),"text", "没有找到相关内容 换个词试试吧");
        if (endCoordinate != null && endCoordinate.length == 2){
            log.info("xhs search device {} not found keyword {}",device.getSerial(),keyword);
            return;
        }

        String[] lastListCoordinate = getCoordinate(new ByteArrayInputStream(baos.toByteArray()),"text", "最新");

        if (lastListCoordinate == null){
            String comments = getTextNodeVaule(new ByteArrayInputStream(baos.toByteArray()), "resource-id", "com.xingin.xhs:id/b3u");//标题
            if(StringUtils.isBlank(comments)){
                throw new Exception("loading exception!");
            }
        } else {
            executeShell(5000,device,"input tap "+lastListCoordinate[0]+" "+lastListCoordinate[1]);
            log.info(log_prefix +"点击最新列表",device.getSerial());
        }

        //滑动屏幕，采集视频
        for(int start=1;start<=swipeNumbers;start++){
            executeShell(device,"input swipe 540 1900 540 0 400");

            if (start % 5 == 0){
                baos = dumpUIForOutPutStream(device,5);
                ByteArrayInputStream inputStream = new ByteArrayInputStream(baos.toByteArray());
                endCoordinate = getCoordinate(inputStream,"text", "- THE END -");
                if (endCoordinate != null && endCoordinate.length == 2){
                    log.info("xhs search device {} keyword {} to the end",device.getSerial(),keyword);
                    break;
                }

                endCoordinate = getCoordinate(new ByteArrayInputStream(baos.toByteArray()),"text", "没有找到相关内容 换个词试试吧");
                if (endCoordinate != null && endCoordinate.length == 2){
                    log.info("xhs search device {} not found keyword {}",device.getSerial(),keyword);
                    break;
                }

                boolean isAVailable = isAvailable(device,new ByteArrayInputStream(baos.toByteArray()));
                if (!isAVailable){
                    try {
                        Thread.sleep(2*60*1000L); //休息两分钟 等待验证码校验
                    } catch (InterruptedException e) {
                        log.error(e.getMessage(),e);
                    }

                    throw new Exception("xhs search device "+device.getSerial()+" unavailable!");
                }
            }
        }

        log.info(log_prefix +"返回搜索页",device.getSerial());
    }

    private static boolean initHome(JadbDevice device) throws Exception {

        for(int backCOunt=0;backCOunt < 10;backCOunt++){
            ByteArrayOutputStream baos = dumpUIForOutPutStream(device,4);

            String[] homeCoordinate = getCoordinate(new ByteArrayInputStream(baos.toByteArray()), "text", "首页", false);

            if (homeCoordinate != null && homeCoordinate.length == 2){
                String[] searchCoordinate = getCoordinate(new ByteArrayInputStream(baos.toByteArray()),"text","搜索笔记、商品和用户",true);
                if (searchCoordinate == null){
                    executeShell(3000,device,"input tap "+homeCoordinate[0]+" "+homeCoordinate[1]);
                }else {
                    executeShell(3000,device,"input tap "+searchCoordinate[0]+" "+searchCoordinate[1]);
                    log.info(log_prefix +"script--点击搜索图标",device.getSerial());
                    return true;
                }
            }
            executeShell(3000,device,"input keyevent 4"); //设置3s间隔，防止退出app

        }
        return false;
    }

    private static boolean checkAvailable(JadbDevice device){

        boolean isAvailable = isAvailable(device);

        if(!isAvailable){ //不可用
            try {
                Thread.sleep(60000L);
            } catch (InterruptedException e) {
                log.error(e.getMessage(),e);
            }
        }
        return isAvailable;
    }

    private static boolean isAvailable(JadbDevice device){
        return isAvailable(device,null);
    }

    private static boolean isAvailable(JadbDevice device, InputStream inputStream){
        String[] coordinate;
        try {
            if (inputStream == null){
                inputStream = dumpUI(device);
            }
            coordinate = getCoordinate(inputStream, "text", "请确认你不是机器人");

            if (coordinate != null){
                log.error("xhs search Jump out captcha, device--{}",device.getSerial());

                executeShell(device,"input tap 190 1110"); //点击关闭验证码
                return false;
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
        return true;
    }
}
